<head>
    	<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
	
	<script type="text/javascript" src="camera.js"></script>
	<script type="text/javascript" src="noise.js"></script>
	<script type="text/javascript" src="landscape.js"></script>
	<script type="text/javascript" src="firtree.js"></script>
	<script type="text/javascript" src="firtree_loader.js"></script>

<script id="shader-fs" type="x-shader/x-fragment">
    precision mediump float;

    void main(void) {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
</script>
<script id="shader-vs" type="x-shader/x-vertex">
    attribute vec3 aVertexPosition;

    uniform mat4 uMMatrix;
    uniform mat4 uVMatrix;
    uniform mat4 uPMatrix;

    void main(void) {
        gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aVertexPosition, 1.0);
    }
</script>


<script id="firtree-fs" type="x-shader/x-fragment">
    precision mediump float;

    varying vec3 n;		
    void main(void) {
	vec3 light_dir = normalize(vec3(1,-1,1));	
	float diffuse = max(0.0,dot(normalize(n), -light_dir));
        gl_FragColor = vec4(0.0) + vec4(diffuse, diffuse, diffuse, 1.0);
    }
</script>
<script id="firtree-vs" type="x-shader/x-vertex">
    attribute vec3 pos;
    attribute vec3 norm;

    uniform mat4 M, V, P;
    uniform vec3 origin;
    uniform float rot;

    varying vec3 n;
    void main(void) {

	vec3 p = pos;

	float cosA = cos(rot), sinA = sin(rot);
	mat2 rm = mat2(cosA, -sinA, sinA,  cosA);
	p.xz = rm * p.xz; 

        gl_Position = P* V* M* vec4(p + origin, 1.0);
	n = norm;
    }
</script>

<script id="landscape-vs" type="x-shader/x-vertex">
    attribute vec3 pos;
    attribute vec3 norm;

    uniform mat4 M;
    uniform mat4 V;
    uniform mat4 P;

    varying vec3 n;
    varying vec2 t;

    void main(void) {
        gl_Position = P * V * M * vec4(pos, 1.0);
	n = norm;
	t = pos.xz / 32.0;
    }
</script>
<script id="landscape-fs" type="x-shader/x-fragment">
    precision mediump float;

    varying vec3 n;
    varying vec2 t;	
    void main(void) {
	vec3 light_dir = normalize(vec3(1,-1,1));	
	float diffuse = max(0.0,dot(normalize(n), -light_dir));
        gl_FragColor = vec4(0.0) + vec4(diffuse, diffuse, diffuse, 1.0);
    }
</script>


<script id="landscape2-vs" type="x-shader/x-vertex">
#line 85
    attribute vec3 pos;
    attribute vec3 norm;

    uniform mat4 M;
    uniform mat4 V;
    uniform mat4 P;

    varying vec3 VertexNormal;
    varying vec3 VertexWorldPos;


vec4 mod289(vec4 x)
{
    return x - floor(x * (1.0 / 289.0)) * 289.0;
}
 
vec4 permute(vec4 x)
{
    return mod289(((x*34.0)+1.0)*x);
}
 
vec4 taylorInvSqrt(vec4 r)
{
    return 1.79284291400159 - 0.85373472095314 * r;
}
 
vec2 fade(vec2 t) {
    return t*t*t*(t*(t*6.0-15.0)+10.0);
}
 
// Classic Perlin noise
float cnoise(vec2 P)
{
	vec4 Pi = floor(vec4(P.x, P.y, P.x, P.y)) + vec4(0.0, 0.0, 1.0, 1.0);
    vec4 Pf = fract(vec4(P.x, P.y, P.x, P.y)) - vec4(0.0, 0.0, 1.0, 1.0);
    Pi = mod289(Pi); // To avoid truncation effects in permutation
    vec4 ix = vec4(Pi.x, Pi.z, Pi.x, Pi.z);
    vec4 iy = vec4(Pi.y, Pi.y, Pi.w, Pi.w);
    vec4 fx = vec4(Pf.x, Pf.z, Pf.x, Pf.z);
    vec4 fy = vec4(Pf.y, Pf.y, Pf.w, Pf.w);
     
    vec4 i = permute(permute(ix) + iy);
     
    vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0;
    vec4 gy = abs(gx) - 0.5 ;
    vec4 tx = floor(gx + 0.5);
    gx = gx - tx;
     
    vec2 g00 = vec2(gx.x,gy.x);
    vec2 g10 = vec2(gx.y,gy.y);
    vec2 g01 = vec2(gx.z,gy.z);
    vec2 g11 = vec2(gx.w,gy.w);
     
    vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
    g00 *= norm.x;  
    g01 *= norm.y;  
    g10 *= norm.z;  
    g11 *= norm.w;  
     
    float n00 = dot(g00, vec2(fx.x, fy.x));
    float n10 = dot(g10, vec2(fx.y, fy.y));
    float n01 = dot(g01, vec2(fx.z, fy.z));
    float n11 = dot(g11, vec2(fx.w, fy.w));
     
    vec2 fade_xy = fade(vec2(Pf.x, Pf.y));
    vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
    float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
    return 2.3 * n_xy;
}
 
// Classic Perlin noise, periodic variant
float pnoise(vec2 P, vec2 rep)
{
    vec4 Pi = floor(vec4(P.x, P.y, P.x, P.y)) + vec4(0.0, 0.0, 1.0, 1.0);
    vec4 Pf = fract(vec4(P.x, P.y, P.x, P.y)) - vec4(0.0, 0.0, 1.0, 1.0);
    Pi = mod(Pi, vec4(rep.x, rep.y, rep.x, rep.y)); // To create noise with explicit period
    Pi = mod289(Pi);        // To avoid truncation effects in permutation
    vec4 ix = vec4(Pi.x, Pi.z, Pi.x, Pi.z);
    vec4 iy = vec4(Pi.y, Pi.y, Pi.w, Pi.w);
    vec4 fx = vec4(Pf.x, Pf.z, Pf.x, Pf.z);
    vec4 fy = vec4(Pf.y, Pf.y, Pf.w, Pf.w);
          
    vec4 i = permute(permute(ix) + iy);
     
    vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ;
    vec4 gy = abs(gx) - 0.5 ;
    vec4 tx = floor(gx + 0.5);
    gx = gx - tx;
     
    vec2 g00 = vec2(gx.x,gy.x);
    vec2 g10 = vec2(gx.y,gy.y);
    vec2 g01 = vec2(gx.z,gy.z);
    vec2 g11 = vec2(gx.w,gy.w);
     
    vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
    g00 *= norm.x; 
    g01 *= norm.y;  
    g10 *= norm.z;  
    g11 *= norm.w;  
     
    float n00 = dot(g00, vec2(fx.x, fy.x));
    float n10 = dot(g10, vec2(fx.y, fy.y));
    float n01 = dot(g01, vec2(fx.z, fy.z));
    float n11 = dot(g11, vec2(fx.w, fy.w));
     
    vec2 fade_xy = fade(vec2(Pf.x, Pf.y));
    vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
    float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
    return 2.3 * n_xy;
}
 
float fbm(vec2 P, int octaves, float lacunarity, float gain)
{
    float sum = 0.0;
    float amp = 1.0;
    vec2 pp = P;

    for(int i = 0; i < 4; i++)
    {
        amp *= gain; 
        sum += amp * cnoise(pp);
        pp *= lacunarity;
    }
    return sum;
 
}
 
    void main(void) {
	VertexNormal = norm;
	float heightmap_scale = 10.0/(64.0-1.0);
	float y_scale = 1.5;
	vec4 modpos;
	modpos.xz = pos.xz;
	modpos.y = y_scale*fbm(heightmap_scale*(modpos.xz+32.0), 4, 2.0, 0.5);
	modpos.w = 1.0;
        gl_Position = P * V * M * vec4(pos, 1.0);
        //gl_Position = P * V * M * modpos;

	//VertexWorldPos = (M * modpos).xyz; 
	VertexWorldPos = (M * vec4(pos,1.0)).xyz; 
    }
</script>
<script id="landscape2-fs" type="x-shader/x-fragment">
#line 228
    precision mediump float;

uniform float heightmap_scale;

//in float height;
varying vec3 VertexNormal;
varying vec3 VertexWorldPos;

//layout (location=0) out vec4 FragColor;


vec4 mod289(vec4 x)
{
    return x - floor(x * (1.0 / 289.0)) * 289.0;
}
 
vec4 permute(vec4 x)
{
    return mod289(((x*34.0)+1.0)*x);
}
 
vec4 taylorInvSqrt(vec4 r)
{
    return 1.79284291400159 - 0.85373472095314 * r;
}
 
vec2 fade(vec2 t) {
    return t*t*t*(t*(t*6.0-15.0)+10.0);
}
 
// Classic Perlin noise
float cnoise(vec2 P)
{
	vec4 Pi = floor(vec4(P.x, P.y, P.x, P.y)) + vec4(0.0, 0.0, 1.0, 1.0);
    vec4 Pf = fract(vec4(P.x, P.y, P.x, P.y)) - vec4(0.0, 0.0, 1.0, 1.0);
    Pi = mod289(Pi); // To avoid truncation effects in permutation
    vec4 ix = vec4(Pi.x, Pi.z, Pi.x, Pi.z);
    vec4 iy = vec4(Pi.y, Pi.y, Pi.w, Pi.w);
    vec4 fx = vec4(Pf.x, Pf.z, Pf.x, Pf.z);
    vec4 fy = vec4(Pf.y, Pf.y, Pf.w, Pf.w);
     
    vec4 i = permute(permute(ix) + iy);
     
    vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0;
    vec4 gy = abs(gx) - 0.5 ;
    vec4 tx = floor(gx + 0.5);
    gx = gx - tx;
     
    vec2 g00 = vec2(gx.x,gy.x);
    vec2 g10 = vec2(gx.y,gy.y);
    vec2 g01 = vec2(gx.z,gy.z);
    vec2 g11 = vec2(gx.w,gy.w);
     
    vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
    g00 *= norm.x;  
    g01 *= norm.y;  
    g10 *= norm.z;  
    g11 *= norm.w;  
     
    float n00 = dot(g00, vec2(fx.x, fy.x));
    float n10 = dot(g10, vec2(fx.y, fy.y));
    float n01 = dot(g01, vec2(fx.z, fy.z));
    float n11 = dot(g11, vec2(fx.w, fy.w));
     
    vec2 fade_xy = fade(vec2(Pf.x, Pf.y));
    vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
    float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
    return 2.3 * n_xy;
}
 
// Classic Perlin noise, periodic variant
float pnoise(vec2 P, vec2 rep)
{
    vec4 Pi = floor(vec4(P.x, P.y, P.x, P.y)) + vec4(0.0, 0.0, 1.0, 1.0);
    vec4 Pf = fract(vec4(P.x, P.y, P.x, P.y)) - vec4(0.0, 0.0, 1.0, 1.0);
    Pi = mod(Pi, vec4(rep.x, rep.y, rep.x, rep.y)); // To create noise with explicit period
    Pi = mod289(Pi);        // To avoid truncation effects in permutation
    vec4 ix = vec4(Pi.x, Pi.z, Pi.x, Pi.z);
    vec4 iy = vec4(Pi.y, Pi.y, Pi.w, Pi.w);
    vec4 fx = vec4(Pf.x, Pf.z, Pf.x, Pf.z);
    vec4 fy = vec4(Pf.y, Pf.y, Pf.w, Pf.w);
          
    vec4 i = permute(permute(ix) + iy);
     
    vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ;
    vec4 gy = abs(gx) - 0.5 ;
    vec4 tx = floor(gx + 0.5);
    gx = gx - tx;
     
    vec2 g00 = vec2(gx.x,gy.x);
    vec2 g10 = vec2(gx.y,gy.y);
    vec2 g01 = vec2(gx.z,gy.z);
    vec2 g11 = vec2(gx.w,gy.w);
     
    vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
    g00 *= norm.x; 
    g01 *= norm.y;  
    g10 *= norm.z;  
    g11 *= norm.w;  
     
    float n00 = dot(g00, vec2(fx.x, fy.x));
    float n10 = dot(g10, vec2(fx.y, fy.y));
    float n01 = dot(g01, vec2(fx.z, fy.z));
    float n11 = dot(g11, vec2(fx.w, fy.w));
     
    vec2 fade_xy = fade(vec2(Pf.x, Pf.y));
    vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
    float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
    return 2.3 * n_xy;
}
 
float fbm(vec2 P, int octaves, float lacunarity, float gain)
{
    float sum = 0.0;
    float amp = 1.0;
    vec2 pp = P;

    for(int i = 0; i < 4; i++)
    {
        amp *= gain; 
        sum += amp * cnoise(pp);
        pp *= lacunarity;
    }
    return sum;
 
}
 
 
float pattern(vec2 p) {
    float l = 2.5;
    float g = 0.4;
    int oc = 10;
     
    vec2 q = vec2( fbm( p + vec2(0.0,0.0),oc,l,g),fbm( p + vec2(5.2,1.3),oc,l,g));
    vec2 r = vec2( fbm( p + 4.0*q + vec2(1.7,9.2),oc,l,g ), fbm( p + 4.0*q + vec2(8.3,2.8) ,oc,l,g));
    return fbm( p + 4.0*r ,oc,l,g);    
}
 
float pattern2( vec2 p, out vec2 q, out vec2 r, float time)
{
    float l = 2.3;
    float g = 0.4;
    int oc = 10; 
     
    q.x = fbm( p + vec2(time,time),oc,l,g);
    q.y = fbm( p + vec2(5.2*time,1.3*time) ,oc,l,g);
     
    r.x = fbm( p + 4.0*q + vec2(1.7,9.2),oc,l,g );
    r.y = fbm( p + 4.0*q + vec2(8.3,2.8) ,oc,l,g);
     
    return fbm( p + 4.0*r ,oc,l,g);
}

void main(void)
{
	vec3 white = vec3(1.0,1.0,1.0);
	vec3 light_dir = normalize(vec3(-1.0,-1.0,1.0));
	vec3 n = normalize(VertexNormal);


	//float heightmap_scale = 10.0/(64.0 - 1.0);
	vec2 wpos = heightmap_scale*(VertexWorldPos.xz + 32.0);
	float eps = 1e-1;
	float h = fbm(heightmap_scale*(VertexWorldPos.xz + 32.0), 4, 2.0, 0.5);
	float horig = h;
	float dx = fbm(wpos + vec2(eps,0.0), 4, 2.0, 0.5) - fbm(wpos - vec2(eps,0.0), 4, 2.0, 0.5); 
	float dz = fbm(wpos + vec2(0.0, eps), 4, 2.0, 0.5) - fbm(wpos - vec2(0.0,eps), 4, 2.0, 0.5);
	float dy  = 2.0*heightmap_scale;
	vec3 detail_normal = normalize(vec3(-dx, dy, dz));
	vec4 res = 0.5*vec4(detail_normal, 1) + 0.5 + vec4(n, 1.0)*0.0000000001;
	gl_FragColor = //vec4(max(0.0,horig)) + 
			vec4(n*vec3(0.00000000001) + detail_normal*vec3(1.00000000001),1);

	n = detail_normal;	

	float slope = 1.5*length(n.xz);
	h = 4.0*h*(1.0-0.9*slope);
	//slope = clamp((h/(1.0+h))*(h/(1.0+h)),0.0,1.0);
	//vec3 c = mix(vec3(0.1, 0.8, 0.3), white, slope);
	vec3 ground = vec3(0.2,0.8,0.2);
	vec3 c = max(ground, mix(ground, vec3(slope), slope));
	//vec3 diffuse = c*max(0.3, dot(normalize(n+detail_normal), -light_dir));
	vec3 diffuse = c*max(0.3, dot(normalize(n), -light_dir));

	gl_FragColor = vec4(diffuse, 1);

}

</script>

<script type="text/javascript">
var gl;
var mvMatrix, pMatrix;
var g_view_mat = lookAt2(new vec3(0,0, 0), new vec3(0,5.25,-20), new vec3(0,1,0));
var g_proj_mat = null;
var g_model1_mat = new mat4();
g_model1_mat.translate(-1.5,0,2); 
var g_model2_mat = new mat4();
g_model2_mat.translate(1.5,0,1); 
var g_model_mat = null;
var g_model1_pos_mat = new mat4();
g_model1_pos_mat.translate(-1.5, 0, 2);
var g_identity_mat = new mat4();

var g_time = 0.0;
var g_dt = 15; // frame is 15ms

var g_terrain = new Object();
var g_firtree = new Object();

function initGL(canvas) {
	try {
		var attribs = { antialias: true };
		var ctxs = [ "webgl", "experimental-webgl" ];
		for(var i=0;i < ctxs.length; ++i) {
			gl = canvas.getContext(ctxs[i], attribs);
			if(gl) break;
		}
            	gl.viewportWidth = canvas.width;
            	gl.viewportHeight = canvas.height;
        } catch (e) {
        }
        if (!gl) {
            alert("Could not initialise WebGL, sorry :-(");
        }
}

const IA_LEFT = 0;
const IA_RIGHT = 1;
const IA_UP = 2;
const IA_DOWN = 3;
var g_InputMap = [ false, false, false, false ];

var g_angle = 0.0;
var g_vert_angle = -20.0;
function UpdateInput() {
	if(g_InputMap[IA_LEFT])
		g_angle += 1.0;
	if(g_InputMap[IA_RIGHT])
		g_angle -= 1.0;
	if(g_InputMap[IA_UP]) {
		g_vert_angle = Math.min(89.0, g_vert_angle+1.0);
	}
	if(g_InputMap[IA_DOWN]) {
		g_vert_angle = Math.max(-89.0, g_vert_angle-1.0);
	}
}

function identityMatrix() {
   	var buf = new ArrayBuffer(Float32Array.BYTES_PER_ELEMENT*16);
	var view32f = new Float32Array(buf); 
	view32f[0] = 1; 
	view32f[1] = 0; 
	view32f[2] = 0; 
	view32f[3] = 0;

	view32f[4] = 0; 
	view32f[5] = 1; 
	view32f[6] = 0; 
	view32f[7] = 0;

	view32f[8] = 0; 
	view32f[9] = 0; 
	view32f[10] = 1; 
	view32f[11] = 0;

	view32f[12] = 0; 
	view32f[13] = 0; 
	view32f[14] = 0; 
	view32f[15] = 1;

	return view32f;
}

function translationFromView(v, tx, ty, tz) {

	v[12] = tx;
	v[13] = ty;
	v[14] = tz;
    	return v;
}

function projectionMatrix2(left, right, bottom, top,near, far)
{
	var x,y,a,b,c,d;
	x = 2.0*near / (right - left);
	y = 2.0*near / (top - bottom);
	a = (right + left) / (right - left);
	b = (top + bottom) / (top - bottom);
	c = -(far + near) / (far - near);
	d = -(2.0*far*near) / (far - near);

	var buf = new ArrayBuffer(Float32Array.BYTES_PER_ELEMENT*16);
	var view32f = new Float32Array(buf); 
	view32f[0] = x; 
	view32f[4] = 0; 
	view32f[8] = a; 
	view32f[12] = 0;

	view32f[0 + 1] = 0; 
	view32f[4 + 1] = y; 
	view32f[8 + 1] = b; 
	view32f[12 + 1] = 0;

	view32f[0+2] = 0; 
	view32f[4+2] = 0; 
	view32f[8+2] = c; 
	view32f[12+2] = d;

	view32f[0+3] = 0; 
	view32f[4+3] = 0; 
	view32f[8+3] = -1; 
	view32f[12+3] = 0;

	return view32f;
}

function getShader(gl, id) {
        var shaderScript = document.getElementById(id);
        if (!shaderScript) {
            return null;
        }

        var str = "";
        var k = shaderScript.firstChild;
        while (k) {
            if (k.nodeType == 3) {
                str += k.textContent;
            }
            k = k.nextSibling;
        }

        var shader;
        if (shaderScript.type == "x-shader/x-fragment") {
            shader = gl.createShader(gl.FRAGMENT_SHADER);
        } else if (shaderScript.type == "x-shader/x-vertex") {
            shader = gl.createShader(gl.VERTEX_SHADER);
        } else {
            return null;
        }

        gl.shaderSource(shader, str);
        gl.compileShader(shader);

        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
            alert(gl.getShaderInfoLog(shader));
            return null;
        }

        return shader;
    }


    var shaderProgram;

    function initShaders() {
        var fragmentShader = getShader(gl, "shader-fs");
        var vertexShader = getShader(gl, "shader-vs");

        shaderProgram = gl.createProgram();
        gl.attachShader(shaderProgram, vertexShader);
        gl.attachShader(shaderProgram, fragmentShader);
        gl.linkProgram(shaderProgram);

        if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
            alert("Could not initialise shaders");
        }

        gl.useProgram(shaderProgram);

        shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
        //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

        shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
        shaderProgram.mMatrixUniform = gl.getUniformLocation(shaderProgram, "uMMatrix");
        shaderProgram.vMatrixUniform = gl.getUniformLocation(shaderProgram, "uVMatrix");
    }




	function InitMatrices() {
		mvMatrix = translationFromView(identityMatrix(), -1.5, 0.0, -1.0);
		var aspect = gl.viewportWidth / gl.viewportHeight;
		pMatrix = projectionMatrix2(-aspect*0.5, aspect*0.5, -.5, .5, .1, 1000.0);
		g_proj_mat = projectionMatrix(-aspect*0.05, aspect*0.05, -.05, .05, .1, 1000.0); 
	}

    	function setMatrixUniforms(shader, m, v, p) {
        	gl.uniformMatrix4fv(shader.mMatrixUniform, false, m.raw());
        	gl.uniformMatrix4fv(shader.vMatrixUniform, false, v.raw());
        	//gl.uniformMatrix4fv(shader.vMatrixUniform, false, v);
        	gl.uniformMatrix4fv(shader.pMatrixUniform, false, p.raw());
    	}

	function InitTerrain() {
		g_terrain.hf = generate_heightfield(64);
		g_terrain.mat = load_landscape_material();
	}
	function InitFirtree() {

		var minv = new vec3(-0.5*g_terrain.hf.size, 0, -0.5*g_terrain.hf.size);	
		var maxv = new vec3(0.5*g_terrain.hf.size, g_terrain.hf.y_scale, 0.5*g_terrain.hf.size);	
		g_firtree.mesh = create_firtree(2000, minv, maxv, g_terrain.hf);
		g_firtree.mat = load_firtree_material();
	}

	function InitInput() {
		var update_map = function(keyCode, val) {
			switch(keyCode) {
				case 37:
					g_InputMap[0] = val;
					break;
				case 39:
					g_InputMap[1] = val;
					break;
        	       	 	case 38:
					g_InputMap[2] = val;
					break;
               		 	case 40:
					g_InputMap[3] = val;
					break;
			}
			
		}
		document.onkeydown = function(event) {
			var keyCode;
  			var new_dir;

  			if(event == null) {	
    				keyCode = window.event.keyCode;
  			}
  			else {
    				keyCode = event.keyCode;
  			}
			update_map(keyCode, true);
		}
		document.onkeyup = function(event) {
			var keyCode;
  			var new_dir;

  			if(event == null) {	
    				keyCode = window.event.keyCode;
  			}
  			else {
    				keyCode = event.keyCode;
  			}
			update_map(keyCode, false);
		}
	}


    var triangleVertexPositionBuffer;
    var squareVertexPositionBuffer;

    function initBuffers() {
        triangleVertexPositionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
        var vertices = [
             0.0,  1.0,  0.0,
            -1.0, -1.0,  0.0,
             1.0, -1.0,  0.0
        ];
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        triangleVertexPositionBuffer.itemSize = 3;
        triangleVertexPositionBuffer.numItems = 3;

        squareVertexPositionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
        vertices = [
             1.0,  1.0,  0.0,
            -1.0,  1.0,  0.0,
             1.0, -1.0,  0.0,
            -1.0, -1.0,  0.0
        ];
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        squareVertexPositionBuffer.itemSize = 3;
        squareVertexPositionBuffer.numItems = 4;
    }


    function drawScene() {

	g_time += g_dt;

	UpdateInput();

	var angle = g_time/1000;
	angle = g_angle*Math.PI / 180.0;	
	var dist = 5;//0.0*(2 + Math.sin(angle));
	dist = g_vert_angle;
	var pos = new vec3(dist*Math.sin(angle), 3, dist*Math.cos(angle));
	//g_view_mat = lookAt(pos, new vec3(0,0, 0));//, new vec3(0,1,0));
	g_view_mat = lookAt2(new vec3(0,0, 0), pos, new vec3(0,1,0));
	


	// update matrices
	var rot = rotationZ4(g_time/200.0);
	g_model1_mat = mat4mul(rot, g_model1_pos_mat);

        gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

	gl.useProgram(shaderProgram);
        gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
        gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
        gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
        //setMatrixUniforms(shaderProgram, g_model1_mat, /*g_view_mat*/mvMatrix, g_proj_mat);
        setMatrixUniforms(shaderProgram, g_model1_mat, g_view_mat, g_proj_mat);
        gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);

        gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
        gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
        //setMatrixUniforms(shaderProgram, g_model2_mat, /*g_view_mat*/mvMatrix, g_proj_mat);
        setMatrixUniforms(shaderProgram, g_model2_mat, g_view_mat, g_proj_mat);
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);

		
        gl.disableVertexAttribArray(shaderProgram.vertexPositionAttribute);
	gl.useProgram(null);


	draw_landscape(g_terrain.hf, g_terrain.mat, g_identity_mat.raw(), g_view_mat.raw(), g_proj_mat.raw());

	draw_firtree(g_firtree.mesh, g_firtree.mat, g_identity_mat.raw(), g_view_mat.raw(), g_proj_mat.raw());
    }



    function webGLStart() {
        var canvas = document.getElementById("xmas-canvas");
	initGL(canvas);
	InitTerrain();
	InitFirtree();
	InitInput();
	InitMatrices();
        initShaders();
        initBuffers();

        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.enable(gl.DEPTH_TEST);

        setInterval(drawScene, g_dt);
    }

</script>

</head>

<body onload="webGLStart();">
    <canvas id="xmas-canvas" style="border: 1px;" width="1280" height="720">
    </canvas>

</body>

